package com.onpositive.storage.managers;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;

import javax.jdo.PersistenceManager;

import com.google.appengine.api.datastore.Blob;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.memcache.Expiration;
import com.google.appengine.api.memcache.MemcacheService;
import com.google.appengine.api.memcache.MemcacheServiceFactory;

public class UnifiedContentProvider {

	private static Expiration expirations = Expiration.byDeltaSeconds(3600);
	private static MemcacheService cacheService;
	private static Map<String, byte[]> cacheServiceSecond = new WeakHashMap<String, byte[]>();
	// private static Cache cache = null;

	public static final String IMAGES_DIR = "/images";
	public static final String RESOURCES_DIR = "/res";

	public static final String CONTENT_KIND = "UnifiedContent";
	public static final String URI_PROP = "mappedReqString";
	public static final String CONTENT_PROP = "content";

	// private static final PersistenceManagerFactory pmfInstance = JDOHelper
	// .getPersistenceManagerFactory("transactions-optional");

	// private static final PersistenceManager pm = pmfInstance
	// .getPersistenceManager();

	// private static final EntityManagerFactory emf = Persistence
	// .createEntityManagerFactory("transactions-optional");
	private static final DatastoreService dss = DatastoreServiceFactory
			.getDatastoreService();

	public static synchronized void storeContentElement(String mappedURI,
			byte[] content) {

		insertIntoCache(mappedURI, content);

		Blob bl = new Blob(content);

		Key kk = KeyFactory.createKey(CONTENT_KIND, mappedURI);

		Entity e = null;

		/*
		 * try { e = dss.get(kk); } catch (EntityNotFoundException ex) { e = new
		 * Entity(kk); }
		 */

		e = new Entity(kk);
		e.setProperty(URI_PROP, mappedURI);
		e.setProperty(CONTENT_PROP, bl);

		dss.put(e);
	}

	private static void insertIntoCache(String mappedURI, byte[] content) {

		synchronized (cacheServiceSecond) {
			if (mappedURI.endsWith(".html") || mappedURI.endsWith(".css")) {
				cacheServiceSecond.put(mappedURI, content);
			}
		}

		initCashe();
		cacheService.put(mappedURI, content, expirations);

	}

	public static synchronized void updateContentElement(String mappedURI,
			byte[] content) {

		// List<Key> keys = new ArrayList<Key>();
		// Query q = new Query(CONTENT_KIND);
		// q.addFilter(URI_PROP, FilterOperator.EQUAL, mappedURI);
		// PreparedQuery pq = dss.prepare(q);
		// Iterator<Entity> i = pq.asIterator();

		// while (i.hasNext()) {
		// Key k = i.next().getKey();
		// keys.add(k);
		// }

		// dss.delete(keys);
		storeContentElement(mappedURI, content);

	}

	public static synchronized void storeContentElement(String mappedURI,
			Reader wikiContent) {
		// if (!uploaded.contains(mappedURI)) {
		// EntityManager em = emf.createEntityManager();

		StringWriter sw = new StringWriter();
		char[] buffer = new char[1024];
		int flag = 0;
		try {
			while ((flag = wikiContent.read(buffer)) != -1) {
				sw.write(buffer, 0, flag);
			}

			String readed = sw.getBuffer().toString();
			// Blob bytes = new Blob(readed.getBytes());
			// UnifiedContentHolder holder = new UnifiedContentHolder(mappedURI,
			// bytes);
			// pm.makePersistent(holder);
			// em.persist(holder);
			storeContentElement(mappedURI, readed.getBytes());
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			// em.close();
		}
		// }
	}

	@SuppressWarnings("unchecked")
	public static synchronized InputStream getContentElementAsStream(
			String mappedUri) {
		return new ByteArrayInputStream(getContentElementAsBytes(mappedUri));
	}

	public static synchronized byte[] getContentElementAsBytes(String mappedUri) {

		byte[] content = extractFromCache(mappedUri);
		if (content != null) {
			return content;
		}

		// Query q = new Query(CONTENT_KIND);
		// q.addFilter(URI_PROP, FilterOperator.EQUAL, mappedUri);
		// PreparedQuery pq = dss.prepare(q);

		// if (pq.countEntities() != 1) {
		// return "Content not found.".getBytes();
		// }
		//
		// Entity e = pq.asSingleEntity();
		// Blob bl = (Blob) e.getProperty(CONTENT_PROP);
		// return bl.getBytes();

		Key kk = KeyFactory.createKey(CONTENT_KIND, mappedUri);
		Entity e = null;
		try {
			e = dss.get(kk);
			Blob bl = (Blob) e.getProperty(CONTENT_PROP);
			byte[] contentFromDataBase = bl.getBytes();
			storeContentElement(mappedUri, contentFromDataBase);
			return contentFromDataBase;
		} catch (EntityNotFoundException ex) {
			return "Content not found.".getBytes();
		}
	}

	private static byte[] extractFromCache(String mappedUri) {

		synchronized (cacheServiceSecond) {
			if (cacheServiceSecond.containsKey(mappedUri)) {
				return cacheServiceSecond.get(mappedUri);
			}
		}

		if (cacheService == null) {
			initCashe();
		}
		if (cacheService.contains(mappedUri)) {
			return (byte[]) cacheService.get(mappedUri);
		}

		return null;
	}

	private static void initCashe() {
		// Map props = new HashMap();
		// props.put(GCacheFactory.EXPIRATION_DELTA, 3600);

		cacheService = MemcacheServiceFactory.getMemcacheService();

		// if (cache == null) {
		// try {
		// cache = CacheManager.getInstance().getCacheFactory()
		// .createCache(props);
		// } catch (CacheException e1) {
		// e1.printStackTrace();
		// }
		// }
	}

	public static synchronized PersistenceManager getPM() {
		return null;// pm;
	}

	public static synchronized void deleteContentElement(String mappedUri) {

		synchronized (cacheServiceSecond) {
			if (cacheServiceSecond.containsKey(mappedUri)) {
				cacheServiceSecond.remove(mappedUri);
			}
		}

		if (cacheService != null) {
			if (cacheService.contains(mappedUri)) {
				cacheService.delete(mappedUri);
			}
		}

		// List<Key> keys = new ArrayList<Key>();
		// Query q = new Query(CONTENT_KIND);
		// q.addFilter(URI_PROP, FilterOperator.EQUAL, mappedUri);
		// PreparedQuery pq = dss.prepare(q);
		// Iterator<Entity> i = pq.asIterator();

		// while (i.hasNext()) {
		// Key k = i.next().getKey();
		// keys.add(k);
		// }
		// dss.delete(keys);

		Key kk = KeyFactory.createKey(CONTENT_KIND, mappedUri);
		dss.delete(kk);
		// pm.deletePersistentAll(holders);
	}

	@SuppressWarnings("unchecked")
	public static synchronized List<String> getContentList() {

		List<String> res = new ArrayList();
		Query q = new Query(CONTENT_KIND);
		PreparedQuery pq = dss.prepare(q);
		Iterator<Entity> i = pq.asIterator();

		while (i.hasNext()) {
			Entity e = i.next();
			String obj = (String) e.getProperty(URI_PROP);
			boolean a = obj.indexOf("/updatesite") != 0;
			if (a) {
				res.add(obj);
			}
		}

		return res;
	}

	public static synchronized boolean isContainContentElement(String mappedURI) {

		// Query q = new Query(CONTENT_KIND);
		// q.addFilter(URI_PROP, FilterOperator.EQUAL, mappedURI);
		// PreparedQuery pq = dss.prepare(q);
		// return pq.countEntities() > 0;

		Key kk = KeyFactory.createKey(CONTENT_KIND, mappedURI);

		try {
			dss.get(kk);
			return true;
		} catch (EntityNotFoundException e) {
			return false;
		}

	}
}
